#include "ads1299_driver.h"

#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "freertos/task.h"
#include "driver/gpio.h"

static const char *TAG = "ads_driver";

#define ESP_INTR_FLAG_DEFAULT 0

spi_device_handle_t spi;

/* - - - - - - - - - - - - - - - -*/

ads1299_drv_handler_t ads1299_drv_handler;
uint8_t dummy_u8 = 0;
uint16_t dummy_len = 1;

// uint16_t log_counter = 0;

volatile static ads1299_rec_status_t m_ads1299_rec_status = REC_OFF;
ads1299_rec_status_t get_rec_status(void){
    return m_ads1299_rec_status;
}

static void IRAM_ATTR drdy_gpio_isr_handler(void *arg)
{    
    // do not do the polling spi here, this function should be quick
    // log_counter++;
    // if(log_counter>=100){
    //     //led_toggle();
    //     log_counter = 0;
    //     // ESP_LOGI(TAG, " gpio_config_ads_drv ");

    //     // gpio_set_level(test_pin,(1-gpio_get_level(test_pin)));
    // }

    ads1299_drv_handler(&dummy_u8,dummy_len);  
}

static void gpio_config_ads_drv(void)
{
    gpio_config_t io_conf = {
        .pin_bit_mask = GPIO_OUTPUT_PIN_SEL,
        .mode = GPIO_MODE_INPUT_OUTPUT,
        .intr_type = GPIO_INTR_DISABLE,
        .pull_down_en = 0,
        .pull_up_en = true};
    gpio_config(&io_conf);

    // DRDY pins:
    gpio_config_t io_conf_2 = {
        .pin_bit_mask = BIT64(ADS_DRDY_PIN),
        .mode = GPIO_MODE_INPUT,
        // for powersave reasons, the GPIO should not be floating, use pullup
        .pull_up_en = true,
        .pull_down_en = false,
        .intr_type = GPIO_INTR_NEGEDGE,
    };
    gpio_config(&io_conf_2);

    gpio_set_level(SPI_CS_0, 1);
#ifdef USE_4_CHIPS
    gpio_set_level(SPI_CS_1, 1);
    gpio_set_level(SPI_CS_2, 1);
    gpio_set_level(SPI_CS_3, 1);
#endif

    //if already installed, then do not need to do this
    // gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);

    gpio_isr_handler_add(ADS_DRDY_PIN, drdy_gpio_isr_handler, (void *)ADS_DRDY_PIN);

    // ESP_LOGI(TAG, " gpio_config_ads_drv ");
}

static void spi_config_ads_drv(void)
{
    esp_err_t ret;
    //    spi_device_handle_t handle;

    // Configuration for the SPI bus
    spi_bus_config_t buscfg;
    memset(&buscfg, 0, sizeof(spi_bus_config_t));
    buscfg.mosi_io_num = PIN_NUM_MOSI;
    buscfg.miso_io_num = PIN_NUM_MISO;
    buscfg.sclk_io_num = PIN_NUM_CLK;

    // Configuration for the SPI device on the other side of the bus
    spi_device_interface_config_t devcfg = {
        .clock_speed_hz = 4000000, // 4M 
        // Note that I use spi speed of 4M, which is slow enough so in the ads1299 driver I do not need to worry about the tSDECODE problem.
        .mode = 1,
        .spics_io_num = -1,
        .queue_size = 4,
        // .command_bits = 0,
        // .address_bits = 0,
    };

    // Initialize the SPI bus
     ret = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
    // ret = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_DISABLED);
    ESP_ERROR_CHECK(ret);

    ret = spi_bus_add_device(SPI2_HOST, &devcfg, &spi);
    ESP_ERROR_CHECK(ret);

    // ESP_LOGI(TAG, " spi_config_ads_drv ");
}

int hardware_config(void)
{
    gpio_config_ads_drv();
    spi_config_ads_drv();
    return 0;
}

void delay_ads_drv(uint32_t period_ms)
{
    vTaskDelay(period_ms / portTICK_PERIOD_MS);
    // ESP_LOGI(TAG, " period_ms %ld ",period_ms);
}

void pin_high(int i)
{
    gpio_set_level(i, 1);
    // ESP_LOGI(TAG, " cs_high ");
}

void pin_low(int i)
{
    gpio_set_level(i, 0);
    // ESP_LOGI(TAG, " cs_low ");
}

#define Dummy_Byte 0x00

/*This should be a polling transmit*/
static int spi_send_one_byte(uint8_t u)
{
    esp_err_t ret = ESP_OK;

    // uint8_t data[3];
    // data[0] = u;

    // spi_transaction_t spi_t;
    // memset(&spi_t, 0, sizeof(spi_t)); // Zero out the transaction
    // spi_t.length = 8;
    // spi_t.tx_buffer = data;

    // // ret = spi_device_acquire_bus(spi,portMAX_DELAY);
    // // assert(ret == ESP_OK);
    // ESP_LOGI(TAG, " 123" );

    // ret = spi_device_polling_transmit(spi, &spi_t);
    // assert(ret == ESP_OK);

    // ESP_LOGI(TAG, " spi_send_one_byte %x ",u);
    return ret;
}

/*This should be a polling transmit*/
static int spi_send_recv(const uint8_t*p_tx_buffer, uint8_t *p_rx_buffer, uint16_t len)
{
    esp_err_t ret;

    spi_transaction_t spi_t;
    memset(&spi_t, 0, sizeof(spi_t)); // Zero out the transaction
    spi_t.length = len * 8;
    spi_t.tx_buffer = p_tx_buffer;
    spi_t.rx_buffer = p_rx_buffer;

    // spi_device_release_bus(spi);  
    // ret = spi_device_acquire_bus(spi,portMAX_DELAY);     // not sure, add on 251013
    // assert(ret == ESP_OK);

    ret = spi_device_polling_transmit(spi, &spi_t);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "spi_device_polling_transmit failed: %s", esp_err_to_name(ret));
        if (ret != ESP_ERR_INVALID_STATE){
            assert(ret == ESP_OK);    
        }
    }    

    // E (20818) spi_master: spi_device_polling_start(949): Cannot send polling transaction while the previous polling transaction is not terminated.
    // sometimes, send "stop recording command" will cause this error, which will cause system reset

    // ret = spi_device_queue_trans(spi, &spi_t, portMAX_DELAY);
    // if (ret != ESP_OK) {
    //     ESP_LOGE(TAG, "Queue transaction failed: %s", esp_err_to_name(ret));
    // }



    // ESP_LOGI(TAG, " spi_send_recv %x  %x  %x ",p_tx_buffer[0],p_tx_buffer[1],p_tx_buffer[2]);
    // ESP_LOGI(TAG, " rx : %x  %x  %x ",p_rx_buffer[0],p_rx_buffer[1],p_rx_buffer[2]);
    return ret;
}

ads1299_t m_ads_arr[CHIP_NUM] = {0};

void ads1299_dev_init(ads1299_drv_t m_drv){
    ads1299_drv_handler = m_drv.callback_handler;
    m_ads_arr[0].hardware_config = hardware_config;// init the spi and gpio

    for (int i = 0; i < CHIP_NUM; i++)
    {
        m_ads_arr[i].pin_low = pin_low;
        m_ads_arr[i].pin_high = pin_high;
        m_ads_arr[i].delay_ms = delay_ads_drv;
        m_ads_arr[i].xfer_one_byte = spi_send_one_byte;
        m_ads_arr[i].xfer = spi_send_recv;
        m_ads_arr[i].START_PIN = ADS_DRV_START_PIN;
        m_ads_arr[i].CS_HARDWARE_PIN = PIN_NOT_USE;

        m_ads_arr[i].CH_NUM = CHANNEL_NUM;
        m_ads_arr[i].SMAPLE_RATE = SMAPLE_RATE_500;
        // m_ads_arr[i].SMAPLE_RATE = 250;
    }

    // set to -1 if not USE
    // m_ads_arr[0].CS_PIN = PIN_NOT_USE;
    m_ads_arr[0].CS_PIN = SPI_CS_0;

#ifdef SPI_CS_1
    m_ads_arr[1].CS_PIN = SPI_CS_1;
#endif
#ifdef SPI_CS_2
    m_ads_arr[2].CS_PIN = SPI_CS_2;
#endif
#ifdef SPI_CS_3
    m_ads_arr[3].CS_PIN = SPI_CS_3;
#endif

    m_ads_arr[0].BIAS_BUFFER = 1;
#ifdef USE_4_CHIPS
    m_ads_arr[1].BIAS_BUFFER = 0;
    m_ads_arr[2].BIAS_BUFFER = 0;
    m_ads_arr[3].BIAS_BUFFER = 0;   
#endif

    ads1299_init_hardware(&m_ads_arr[0]);// just do onece

    // for (int i = 0; i < CHIP_NUM; i++)
    // {
    //     ads1299_set_leadoff_detection(&m_ads_arr[i]);


    //         // printf("slkjflkdsjfj - - -- - --- \r\n");
    //     ESP_LOGI(TAG, "slkjflkdsjfj - - -- - --- \r\n ");

    // }    


    for (int i = 0; i < CHIP_NUM; i++)
    {
        ads1299_setup(&m_ads_arr[i]);
    }    

    // for (int i = 0; i < CHIP_NUM; i++)
    // {
    //     ads1299_setup_test_signal(&m_ads_arr[i]);
    // } 
    
    // ads_start_by_start_pin(&m_ads_arr[0]);// start the first will be fine, because all START pins wired together 
}

void ads1299_dev_start_recording(void){
    for (int i = 0; i < CHIP_NUM; i++)
    {
        ads1299_set_RDATAC(&m_ads_arr[i]);
    }
    ads_start_by_start_pin(&m_ads_arr[0]);// start the first will be fine, because all START pins wired together 
    m_ads1299_rec_status = REC_ON;
}

void ads1299_dev_stop_recording(void){
    for (int i = 0; i < CHIP_NUM; i++)
    {
        ads1299_stop_recording(&m_ads_arr[i]);
    }   
    m_ads1299_rec_status = REC_OFF;
}

void ads1299_drv_check_id(void){
    for (int i = 0; i < CHIP_NUM; i++){
        ads1299_get_id(&m_ads_arr[i]);
        ESP_LOGI(TAG, "chip-%d  revId : %d ",i, m_ads_arr[i].id.revId); // should be 1
        ESP_LOGI(TAG, "chip-%d  devId : %d ",i, m_ads_arr[i].id.devId); //shold be 3 
        ESP_LOGI(TAG, "chip-%d  nuCh : %d ",i, m_ads_arr[i].id.nuCh); // 2:8channels, 1:6channels, 0:4channels
    }
}

void ads1299_drv_get_leadoff_status_rx(uint8_t * rx){
    for (int i = 0; i < CHIP_NUM; i++){
        ads1299_get_leadoff_status(&m_ads_arr[i],&rx[2*i]);
    }
}

void ads1299_drv_get_leadoff_status(void){
    uint8_t loff[2*CHIP_NUM] = {0};
    for (int i = 0; i < CHIP_NUM; i++){
        ads1299_get_leadoff_status(&m_ads_arr[i],&loff[2*i]);
        ESP_LOGI(TAG, "- %x, %x ",loff[2*i],loff[2*i+1]);
    }
}
        


// make sure the rx buff longer than 27*CHIP_NUM bytes
// use this in RDATAC mode
void ads1299_drv_get_data(char * rx){
    for (int i = 0; i < CHIP_NUM; i++){
        ads1299_get_data(&m_ads_arr[i],(uint8_t*) &rx[i*DATA_PACKAGE_LEN]);
    }        
}

// make sure the rx buff longer than 32*CHIP_NUM bytes
// use this in RDATAC mode
// make sure the rx buff longer than 3*CHIP_NUM bytes
void ads1299_drv_get_data_int_array(int * rx_int,uint8_t *rx_status){
    
    for (int i = 0; i < CHIP_NUM; i++){
        ads1299_drv_get_data_convert_int_array(&m_ads_arr[i],&rx_int[i*8],&rx_status[i*3]);
        // ESP_LOG_BUFFER_HEX(TAG, &rx_int[i*8], 8);
    }        
}
